#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Provides authentication routines
"""
import hashlib
from logging import debug

try:
    import ldap
except:
    pass

try:
    import win32com.client
except ImportError:
    pass

from tack.db import query
from tack.lib import default401, env_keys

## TODO:  cull this
def authen(app, sources=[], handle401=default401):
    def authen_app(environ, start_response):
        """
        Looks in cookie 'a' for a string like this:
        someusername:somepassword
        which is set my the result of a call /api/login

        It then cyles through the provided sources, and when it
        finds one that successfully authenticates, sets REMOTE_USER and
        returns, otherwise it returns a 401 which prompts for the password.

        The password in 'a' must be plain text. The hash value is stored
        in the database, but all other auth mechanism (ako, ldap) must
        be given the password in plain text.
        """
        try:
            username, password = environ['cookies']['a'].split(':')
        except:
            return handle401(environ, start_response)
        for source in sources:
            if source(username, password, environ):
                environ["REMOTE_USER"] = username
                return app(environ, start_response)
        return handle401(environ, start_response)            
    return authen_app


def basic_authen(app, sources=[], handle401=default401):
    """ Creates an app that requires HTTP_AUTHORIZATION.

    """
    def inner(environ, start_response):
        auth = environ.get(env_keys.http_auth)
        if auth is None:
            return handle401(environ, start_response)
        user, passwd = auth[6:].strip().decode('base64').split(':')
        for source in sources:
            if source(user, passwd, environ):
                environ[env_keys.remote_user] = user
                return app(environ, start_response)
        return handle401(environ, start_response)
    return inner


auth_check_sql = """
SELECT A.login_id, A.login, A.login_name 
FROM auth_login A
WHERE A.login = '%s'
AND A.password_hash = '%s'
"""


def dbauthen(u, p, environ={}):
    """
    Looks up a user based on the username and an sha512 hash of the
    given password.
    """
    p = hashlib.sha512(p).hexdigest()
    sql = auth_check_sql
    try:
        return bool( query(environ['connection'], sql % (u, p) ))
    except KeyError:
        return False

def akoauthen(u,p, environ={}):
    """
    Takes the given user and password and attempts a call to AKO
    Authentication to verify the validity.
    """
    return (win32com.client.Dispatch("AkoAuth.Verify").ValidUser(u,p)[0]
            if 'win32com' in locals() else False)


def ldapauthen(u, p, environ={}):
    """
    Takes the given user and password and attempts to bind to the
    provided LDAP server to verify.
    """
    # This is just a sketch, we'll see where we go from here
    con = ldap.initialize("ldap://ourldapserver.sktcorp.com:389")
    try:
        con.simple_bind_s(who=u, cred=p)
        return true
    except ldap.INVALID_CREDENTIALS:
        return false
    except Exception, e:
        debug("LDAP Auth Error: %s", str(e))
        return false
